/******************************************************************************
 * Copyright (c) 2018 Philipp Schubert.
 * All rights reserved. This program and the accompanying materials are made
 * available under the terms of LICENSE.txt.
 *
 * Contributors:
 *     Philipp Schubert and others
 *****************************************************************************/

#ifndef PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_TYPESTATEDESCRIPTION_H
#define PHASAR_PHASARLLVM_DATAFLOW_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_TYPESTATEDESCRIPTION_H

#include "phasar/PhasarLLVM/Utils/DataFlowAnalysisType.h"

#include <set>
#include <string>

namespace llvm {
class CallBase;
} // namespace llvm

namespace psr {

struct TypeStateDescriptionBase {
  virtual ~TypeStateDescriptionBase() = default;

  [[nodiscard]] virtual bool isFactoryFunction(llvm::StringRef F) const = 0;
  [[nodiscard]] virtual bool isConsumingFunction(llvm::StringRef F) const = 0;
  [[nodiscard]] virtual bool isAPIFunction(llvm::StringRef F) const = 0;
  [[nodiscard]] virtual std::string getTypeNameOfInterest() const = 0;
  [[nodiscard]] virtual std::set<int>
  getConsumerParamIdx(llvm::StringRef F) const = 0;
  [[nodiscard]] virtual std::set<int>
  getFactoryParamIdx(llvm::StringRef F) const = 0;
  [[nodiscard]] virtual DataFlowAnalysisType analysisType() const = 0;
};

/**
 * Interface for a type state problem to be used with the IDETypeStateAnalysis.
 * It needs to provide a finite state machine to handle state changes and a list
 * of functions that are relevant to the analyzed api.
 * Factory functions are those functions which generate objects/variables of
 * target type, e.g. file handles generated by fopen().
 * Consuming functions operate on objects/variables of target type, e.g.
 * fwrite(). Functions that are both factory and consumer, e.g. freopen(),
 * cannot be modeled by this interface, since analyzing such functions correctly
 * introduces dependencies that cannot be solved by a distributive framework
 * such as IDE.
 *
 * @see CSTDFILEIOTypeStateDescription as an example of type state description.
 */
template <typename StateTy>
struct TypeStateDescription : public TypeStateDescriptionBase {
  /// Type for states of the finite state machine
  using State = StateTy;
  ~TypeStateDescription() override = default;

  /**
   * @brief For a given function name (as a string token) and a state, this
   * function returns the next state.
   */
  [[nodiscard]] virtual State getNextState(llvm::StringRef Tok,
                                           State S) const = 0;
  [[nodiscard]] virtual State
  getNextState(llvm::StringRef Tok, State S,
               const llvm::CallBase * /*CallSite*/) const {
    return getNextState(Tok, S);
  }

  [[nodiscard]] virtual State bottom() const = 0;
  [[nodiscard]] virtual State top() const = 0;

  /**
   * Represents the uninitialized state of an object, e.g. allocation of a file
   * handle
   */
  [[nodiscard]] virtual State uninit() const = 0;

  /**
   * Represents the error state of an object
   */
  [[nodiscard]] virtual State error() const = 0;
};

} // namespace psr

#endif
